package com.sun.tspalgorithm;

import com.sun.tspalgorithm.entity.City;
import com.sun.tspalgorithm.entity.CityManager;
import com.sun.tspalgorithm.entity.Tour;
import com.sun.tspalgorithm.util.TestDraw;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

@SpringBootApplication
public class TsPalgorithmApplication {

    // metropolis
    public static double acceptanceProbability(Double energy, Double newEnergy, double temperature) {
        // If the new solution is better, accept it
        if (newEnergy < energy) {
            return 1.0;
        }
        // If the new solution is worse, calculate an acceptance probability
        return Math.exp((energy - newEnergy) / temperature);
    }

    //初始化地图
    public static void initCities() throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("data/n20w20.005.txt"));
        String line = null;
        int times = 0;
        String firstLine = null;
        while ((line = br.readLine()) != null) {
            times++;
            if (times >= 7) {
                if (times == 7) {
                    firstLine = line;
                }
                String[] token = line.trim().split("      ");
                if (Integer.parseInt(token[0]) != 999) {
                    System.out.println(line);
                    City city = new City(Double.parseDouble(token[1]), Double.parseDouble(token[2]));
                    CityManager.addCity(city);
                } else {
                    System.out.println(firstLine);
                    CityManager.addCity(CityManager.getCity(0));
                }
            }
        }
    }

    public static void main(String[] args) {
        try {
            initCities();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        // 初始温度
        double temp = 1000000;

        // 冷却系数
        double coolingRate = 0.001;

        // 初始化最初的路线
        Tour currentSolution = new Tour();
        currentSolution.generateIndividual();

        System.out.println("InitialTour：" + currentSolution);
        System.out.println("Initial solution distance: " + currentSolution.getDistance());

        // 设置最初的最佳情况
        Tour best = new Tour(currentSolution.getTour());

        int num = 0;

        // 循环直至温度冷却
        while (temp > 1) {
            num++;
            //迭代
            for (int i = 0; i < 1000; i++) {
                //新
                Tour newSolution = new Tour(best.getTour());
                int tourPos1 = (int) (newSolution.tourSize() * Math.random());
                int tourPos2 = (int) (newSolution.tourSize() * Math.random());
                while (tourPos1 == tourPos2 || tourPos1 == 0 || tourPos1 == 11 || tourPos2 == 0 || tourPos2 == 11 || tourPos1 == 21 || tourPos2 == 21) {
                    tourPos1 = (int) (newSolution.tourSize() * Math.random());
                    tourPos2 = (int) (newSolution.tourSize() * Math.random());
                }
                City citySwap1 = newSolution.getCity(tourPos1);
                City citySwap2 = newSolution.getCity(tourPos2);
                newSolution.setCity(tourPos2, citySwap1);
                newSolution.setCity(tourPos1, citySwap2);

                Double currentEnergy = best.getDistance();
                Double newEnergy = newSolution.getDistance();

                if (newEnergy < currentEnergy) {
                    best = new Tour(newSolution.getTour());
                } else {
                    if (acceptanceProbability(currentEnergy, newEnergy, temp) > Math.random()) {
                        best = new Tour(newSolution.getTour());
                    }
                }
            }
            // 冷却
            temp *= 1 - coolingRate;
        }

        System.out.println("Final solution distance: " + best.getDistance());
        System.out.println("FinalTour: " + best);
        System.out.println("迭代次数：" + num);

        new TestDraw(best.getTour());
    }


}
